#include "lua_editor_extension.hpp"
#include "data/editor_data.hpp"
#include "scripting/scripting_api.h"
#include "scripting/scripting_module.h"

#include "lua.hpp"
#include "utils/log.hpp"
#include <LuaBridge/LuaBridge.h>

LuaEditorExtension::LuaEditorExtension(EditorTarget type, std::string title, const std::string &script_path):IEditorScript(type, std::move(title), std::move(script_path), g_current_module)
{
    
}

LuaEditorExtension::~LuaEditorExtension()
{
    
}

#define LUA_ERROR_CHK(x) \
do { \
    luabridge::LuaResult r = (x); \
    if (!r) { \
        auto msg = r.errorMessage(); \
        L_ERROR("Lua error: %s", msg.c_str()); \
    } \
} while(0)

void LuaEditorExtension::execute(const void *arg)
{
    try {
        luabridge::LuaRef main = luabridge::getGlobal(l_, "main");
        if (main.isCallable()) {
            switch (apply_target_) {
            case IEditorScript::eItem: LUA_ERROR_CHK(main((const ItemNode*)arg)); break;
            case IEditorScript::eDay:  LUA_ERROR_CHK(main((const DayLevelNode*)arg)); break;
            case IEditorScript::eMonth:LUA_ERROR_CHK(main((const MonthLevelNode*)arg)); break;
            case IEditorScript::eYear: LUA_ERROR_CHK(main((const YearLevelNode*)arg)); break;
            case IEditorScript::eCount: break;
            }
        }
    } catch (std::exception &e) {
        L_ERROR("Failed to call lua script!");
    }
}

IScript* LuaEditorExtension::create(EditorTarget target, std::string title, const std::string_view &code, const std::string &script_path)
{
    auto ext = new LuaEditorExtension(target, std::move(title), script_path);
    if (!ext->compile(code))
    {
        delete ext;
        ext = nullptr;
    }
    return ext;
}

bool LuaEditorExtension::compile(const std::string_view& code) const
{
        int r = luaL_loadbuffer(l_, code.data(), code.length(), "script.lua");
    if (r != LUA_OK) {
        const char *errmsg = lua_tolstring(l_, -1, nullptr);
        if (errmsg != nullptr)
            L_ERROR("lua load error: %s", errmsg);
        lua_pop(l_, 1);
    }
    else
    {
        r = lua_pcall(l_, 0, 0, 0);
        if (r != LUA_OK) {
            const char *errmsg = lua_tolstring(l_, -1, nullptr);
            if (errmsg != nullptr)
                L_ERROR("lua execute error: %s", errmsg);
            lua_pop(l_, 1);
        }
    }
    return r == LUA_OK && lua_getglobal(l_, "main") == LUA_TFUNCTION;
}
